home *** CD-ROM | disk | FTP | other *** search
- /*** tooltips.c ***
- Balloon help (ToolTips) in C. Just a demo of what's possible.
-
- An example of FlyByHintHelpFromWindow & FlyByHintHelpFromClass.
- In C you need to do some subclassing/superclassing.
-
- The balloon functions are used in DlgWinWndProc & ChildSubProc
-
- No copyrights claimed. Donated to the public domain.
-
- Author:
- Alfons Hoogervorst
-
- E-mail:
- 2:500/121.6252 (Fido)
- a.hoogervorst@dosgg.nl (Internet)
-
- BBS:
- DOSBoss West aka The C Programmers Board. Syshost Alex Stienstra
- 31-20-6124530, V32b,V42b,CM,XA, 8 data bits, no parity, 1 stop bitt
-
- Necessary files:
- tooltips.c - This file
- tooltips.rh - Resource header file
- golfiery.h - All definitions for golfiery
- tooltips.rc - resource script
- golfiery.dll - golfiery DLL
- golfiery.lib - Import library
-
- Last revised:
- March/April, 1995
-
- Remarks:
- Use smart callbacks.
-
- Special shoutouts:
- Harry Gijzen - Look at the procs RegisterNewFlyByHintClass,
- NewFlyByHintWndProc (Superclassing) & SubclassAllchilds,
- ChildSubProc (Subclassing)
- Rob de Voer
- Erik Baas
- Fabio Cereda Cordeiro
- *******************/
-
- #include <windows.h>
- #include "golfiery.h"
- #include "tooltips.rh"
-
- /*** Classnames & property strings ***/
- #define DLGCLASSNAME "Ahii_DlgFlyByHintInC"
- #define BALLOONDLL "GOLFIERY.DLL"
-
- /*** Class name for new balloon window ***/
- #define NEWFLYBYHINTCLASSNAME "nAhii_FlyByHint"
-
- /*** Prototypes ***/
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- /*** DLL functions ***/
- BOOL RegisterDlgWin (void);
- BOOL RegisterNewFlyByHintClass (void);
-
- LRESULT CALLBACK _export DlgWinWndProc(HWND, UINT, WPARAM, LPARAM);
- LRESULT CALLBACK _export NewFlyByHintWndProc(HWND, UINT, WPARAM, LPARAM);
- LRESULT CALLBACK _export ChildSubProc(HWND, UINT, WPARAM, LPARAM);
-
- void DlgWin_OnCommand(HWND, WORD);
- void DlgWin_OnPaint(HWND, LPRECT);
-
- void SubclassAllChilds(HWND);
- #ifdef __cplusplus
- }
- #endif
-
-
- /*** Some global variables ***/
- static HINSTANCE _hInst;
- static HWND _hwndMain;
- static BOOL _fOtherClass = FALSE;
- static BOOL _fToolTip = TRUE;
- static WNDPROC _lpfnOldProc;
- char painttext[] = "Area managed by dialog";
- int painttextlen;
-
-
- int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
- LPSTR lpszCmdLine, int nCmdShow)
- {
- MSG message;
-
- _hInst = hInstance;
-
- hPrevInstance = hPrevInstance;
- lpszCmdLine = lpszCmdLine;
-
- // First time initialization
- if ( !RegisterDlgWin() || !RegisterNewFlyByHintClass() )
- return -1;
-
- // Calculate text length
- painttextlen = lstrlen(painttext);
- _hwndMain = CreateDialogParam(_hInst, MAKEINTRESOURCE(IDD_MAINDIALOG),
- NULL, NULL, NULL);
- if ( !_hwndMain ) return -1;
-
- // Windows passes a CmdShow parameter to the program.
- ShowWindow(_hwndMain, nCmdShow);
- UpdateWindow(_hwndMain);
-
- // Run Message Loop
- while ( GetMessage(&message, 0, 0, 0) )
- {
- // If main window will contain modeless dialogs we must call
- // this function. Otherwise TABBING not possible.
- if ( IsDialogMessage(_hwndMain, &message) ) continue;
-
- // Otherwise pass to normal message processing
- TranslateMessage(&message);
- DispatchMessage(&message);
- }
- return message.wParam;
- }
-
-
- /*** RegisterDlgWin ***
- Registers our main window. Ofcourse a tribute to Charles Petzold.
- ***********************/
- BOOL RegisterDlgWin(void)
- {
- WNDCLASS wndclass;
-
- wndclass.style = CS_HREDRAW | CS_VREDRAW;
- wndclass.lpfnWndProc = (WNDPROC) DlgWinWndProc;
-
- /*** Extra window and class bytes ***/
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = DLGWINDOWEXTRA; // Necessary.
-
- wndclass.hInstance = _hInst;
- wndclass.hIcon = LoadIcon(_hInst, MAKEINTRESOURCE(IDI_MAINDIALOG));
- wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
- wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
-
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = DLGCLASSNAME;
-
- /*** Try to register window ***/
- return (RegisterClass(&wndclass));
- }
-
-
- /*** RegisterNewFlyByHintClass ***
- Assorted techniques :-). First retrieves the HINSTANCE of Golfiery.
- Next we get the info about the balloon window class, and use the
- returned info for our new superclassed balloon. Actually the
- superclassed balloon has just another color. So it does nothing
- special at all. (We need to provide a window procedure!)
- ********************************/
- BOOL RegisterNewFlyByHintClass(void)
- {
- WNDCLASS wndclass;
- HINSTANCE hInstGolfiery;
-
- /*** Get instance handle of the balloon dll ***/
- hInstGolfiery = LoadLibrary(BALLOONDLL);
- FreeLibrary(hInstGolfiery);
-
- if ( !GetClassInfo(hInstGolfiery, FLYBYHINTCLASSNAME, &wndclass) )
- return 0;
-
- /*** This class isn't global, clear bit ***/
- wndclass.style &= ~CS_GLOBALCLASS;
-
- /*** New class will be valid for this instance only ***/
- _lpfnOldProc = wndclass.lpfnWndProc;
- wndclass.lpfnWndProc = NewFlyByHintWndProc;
- wndclass.hInstance = _hInst;
-
- /*** Greenish color. Was searching for a strawberry color.
- couldn't find an appropriate color :-( ***/
- wndclass.hbrBackground = CreateSolidBrush(RGB(202, 243, 203)) ;
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = NEWFLYBYHINTCLASSNAME;
-
- return (RegisterClass(&wndclass));
- }
-
-
- /*** DlgWinWndProc ***
- Handles all main window messages. The dialog also manages a hot spot
- area for tooltip info. Take a look at it's WM_MOUSEMOVE handler.
- **********************/
- LRESULT CALLBACK _export DlgWinWndProc(HWND hDlg, UINT uMsg, WPARAM wParam,
- LPARAM lParam)
- {
- static BOOL fSubclassed;
- static RECT rcManagedArea;
- BOOL fCallDefault = TRUE;
- LRESULT lResult = 0; // 0 means handled
-
- switch ( uMsg )
- {
-
- /*** In show window we subclass all controls that need the
- special tooltips. ***/
- case WM_SHOWWINDOW:
- CheckDlgButton(hDlg, IDC_TOGGLEHELP, (UINT)_fToolTip);
- CheckDlgButton(hDlg, IDC_OTHERCLASS, (UINT)_fOtherClass);
-
- /*** Not subclassed yet ***/
- if ( !fSubclassed ) {
- GetClientRect(GetDlgItem(hDlg, 800), &rcManagedArea);
- MapWindowPoints(GetDlgItem(hDlg, 800), hDlg,
- (LPPOINT)&rcManagedArea, 2);
-
- /*** Destroy the "managed area window". We just need it for
- client coords ***/
- DestroyWindow(GetDlgItem(hDlg, 800));
- SubclassAllChilds(hDlg);
- fSubclassed++;
- }
- break;
-
- case WM_PAINT:
- DlgWin_OnPaint(hDlg, &rcManagedArea);
- break;
-
- case WM_MOUSEMOVE:
- if ( _fToolTip )
- if (PtInRect(&rcManagedArea, *((LPPOINT)&lParam))) {
- RECT rcWindow;
-
- rcWindow = rcManagedArea;
- MapWindowPoints(hDlg, 0, (LPPOINT)&rcWindow, 2);
-
- if ( _fOtherClass ) FlyByHintFromClass(_hInst,
- NEWFLYBYHINTCLASSNAME, _hwndMain, &rcWindow, painttext);
- else FlyByHint(_hwndMain, &rcWindow, painttext);
- }
- break;
-
- case WM_COMMAND: // Dialog comands
- DlgWin_OnCommand(hDlg, wParam);
- break; // fCallDefault = TRUE
-
- case WM_DESTROY:
- PostQuitMessage(0);
- fCallDefault = FALSE;
- break;
- }
-
- // if fCallDefault is TRUE we will call DefWindowProc (for default
- // window behaviour
- if ( fCallDefault ) lResult = DefWindowProc(hDlg, uMsg, wParam, lParam);
- return lResult;
- }
-
-
- /*** NewFlyByHintWndProc ***
- The superclass' window procedure
- **************************/
- LRESULT CALLBACK _export NewFlyByHintWndProc(HWND hFlyByHint, UINT uMsg,
- WPARAM wp, LPARAM lp)
- {
- static HFONT hFont;
-
- switch ( uMsg ) {
- case WM_CREATE:
- {
- LOGFONT logfont;
- int c;
-
- /*** Clear out logfont struct. I didn't want to include
- yet another header file ***/
- for (c = 0; c < sizeof logfont; c++) ((LPBYTE)&logfont)[c] = 0;
- logfont.lfItalic = 1;
- lstrcpy(logfont.lfFaceName, "Arial");
- hFont = CreateFontIndirect(&logfont);
- }
- break;
-
- /*** WM_GETFONT returns font handle. It's not necessary to pass it to
- default handler. Nor is it necessary to check if hFont is
- valid.
-
- WM_GETFONT is sent by the WM_PAINT handling code.
- if hFont == 0 the WM_PAINT code uses
- GetStockObject(ANSI_VAR_FONT) ***/
- case WM_GETFONT:
- return (LRESULT)hFont;
-
- case WM_DESTROY:
- if (hFont) DeleteObject(hFont);
- break;
- }
-
- /*** Call old procedure for old behaviour ***/
- return CallWindowProc(_lpfnOldProc, hFlyByHint, uMsg, wp, lp);
- }
-
-
- /*** DlgWin_OnCommand ***
- Handler of control notification messages
- *************************/
- void DlgWin_OnCommand(HWND hDialog, WORD wId)
- {
- switch ( wId ) {
- case IDC_TOGGLEHELP:
- _fToolTip = IsDlgButtonChecked(hDialog, IDC_TOGGLEHELP);
- break;
- case IDC_OTHERCLASS:
- _fOtherClass = IsDlgButtonChecked(hDialog, IDC_OTHERCLASS);
- break;
- }
- }
-
-
- /*** DlgWin_OnPaint ***
- Paints the dialog. Yes. It actually paints on the dialog.
- ***********************/
- void DlgWin_OnPaint(HWND hDlg, LPRECT rcManagedArea)
- {
- PAINTSTRUCT ps;
- DWORD dwExt;
-
- BeginPaint(hDlg, &ps);
- Rectangle(ps.hdc, rcManagedArea->left, rcManagedArea->top,
- rcManagedArea->right, rcManagedArea->bottom);
-
- SelectObject(ps.hdc, GetStockObject(SYSTEM_FONT));
- SetBkMode(ps.hdc, OPAQUE);
- dwExt = GetTextExtent(ps.hdc, painttext, painttextlen);
-
- SetTextAlign(ps.hdc, TA_LEFT | TA_BASELINE);
- TextOut(ps.hdc, 4 * GetSystemMetrics(SM_CXBORDER) + rcManagedArea->left,
- rcManagedArea->top + ((int)HIWORD(dwExt)/2), painttext,
- painttextlen);
-
- EndPaint(hDlg, &ps);
- }
-
-
- /*** SubclassAllChilds ***
- Subclasses all childs. I don't store the old pointer. I just
- make a call to the class' old proc (*not* the window's old proc)
- **************************/
- void SubclassAllChilds(HWND hDialog)
- {
- HWND hwndChild = GetWindow(hDialog, GW_CHILD);
-
- while ( hwndChild ) {
- if ( GetWindowWord(hwndChild, GWW_ID) < 200 )
- SetWindowLong(hwndChild, GWL_WNDPROC, (LONG)ChildSubProc);
- hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
- }
- }
-
-
-
- /*** ChildSubProc ***
- Almost all messages to controls are routed to this window procedure
- *********************/
- LRESULT CALLBACK _export ChildSubProc(HWND hChild, UINT uMsg, WPARAM wp,
- LPARAM lp)
- {
- /*** Get "old" procedure ***/
- WNDPROC lpfnOldProc = (WNDPROC)GetClassLong(hChild, GCL_WNDPROC);
-
- /*** First let old procedure handle the message ***/
- LRESULT lResult = CallWindowProc(lpfnOldProc, hChild, uMsg, wp, lp);
-
- int id = GetWindowWord(hChild, GWW_ID);
-
- /*** Statics don't do mouse moves, we have to "enable" them. Instead
- returning HTTRANSPARENT we return HTCLIENT. It's a little
- simplistic, if the static has a border we should also test if the
- mouse is in the non-client area ***/
- if ( (id == IDC_STATICPOINT) &&
- (uMsg == WM_NCHITTEST) &&
- (lResult == HTTRANSPARENT) )
- return HTCLIENT;
-
- /*** Just need to trap the WM_MOUSEMOVE ***/
- if ( uMsg == WM_MOUSEMOVE )
- if ( _fToolTip ) {
- RECT rcWindow;
- char buf[50];
-
- buf[0] = 0;
-
- /*** Get screen coordinates of control ***/
- GetWindowRect(hChild, &rcWindow);
-
- /*** Get the string associated with this control ***/
- LoadString(_hInst, IDS_TEXT_HELP + id, (LPSTR)&buf, sizeof buf);
- if (_fOtherClass)
- FlyByHintFromClass(_hInst, NEWFLYBYHINTCLASSNAME, _hwndMain, &rcWindow, buf);
- else
- FlyByHintFromWindow(_hwndMain, hChild, buf);
- }
-
- return lResult;
- }
-
-